import { gsap } from 'gsap'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { onBeforeUnmount, Ref, ref, shallowRef, watch } from 'vue'
export function useViewpoint(
  containerRef: Ref<HTMLDivElement | undefined>,
  model: Ref<THREE.Object3D | null>,
  mainControls: Ref<OrbitControls | null>,
) {
  const loadMap = async (path: string) => {
    return new Promise<THREE.Texture>((resolve, reject) => {
      const loader = new THREE.TextureLoader()
      import(`@/assets/viewpoint_map/${path}.png`).then((res) => {
        loader.load(
          res.default,
          (texture) => {
            resolve(texture)
          },
          undefined,
          (error) => {
            console.error('Error loading texture:', error)
            reject(error)
          },
        )
      })
    })
  }
  const width = ref(100)
  const height = ref(100)
  const controls = ref<OrbitControls | null>(null)
  const renderer = shallowRef<THREE.WebGLRenderer | null>(null)
  const scene = shallowRef<THREE.Scene | null>(null)
  const camera = shallowRef<THREE.OrthographicCamera | null>(null)
  const toolCube = shallowRef<THREE.Mesh | null>(null)
  const toolMaterials = shallowRef<THREE.MeshBasicMaterial[]>([])

  watch(model, async (newModel) => {
    if (newModel) {
      await init()
      initMainModelInfo()
      console.log(mainControls.value)
      window.addEventListener('click', onClick)
      setCamera()
      mainControls.value?.addEventListener('change', setCamera)
    }
  })

  // 通过主模型和主相机的位置计算视点工具相机的位置
  const setCamera = () => {
    if (!camera.value || !mainControls.value) return
    const relativePosition = mainControls.value.object.position
      .clone()
      .sub(modelCenter.value)
      .normalize()
      .multiplyScalar(5)
    // 设置 viewpointCamera 的位置为 threeModel 的位置加上相对位置
    camera.value.position.copy(relativePosition)

    const bbox = new THREE.Box3().setFromObject(toolCube.value!)
    const center = bbox.getCenter(new THREE.Vector3())

    camera.value.lookAt(center)
    // 可选：同步旋转
    camera.value.rotation.copy(mainControls.value?.object.rotation)
    controls.value?.target.set(center.x, center.y, center.z)
    controls.value?.update()
  }

  function animate() {
    renderer.value?.setClearColor(0x1f1f1f, 1)
    renderer.value?.setViewport(0, 0, width.value, height.value)
    controls.value?.update()
    renderer.value?.render(scene.value!, camera.value!)
  }
  const init = async () => {
    width.value = containerRef.value?.clientWidth || 100
    height.value = containerRef.value?.clientHeight || 100

    initScene()

    await initToolCube()

    initCamera()

    initLight()

    initRender()

    initControls()
  }

  const initScene = () => {
    scene.value = new THREE.Scene()
    scene.value.background = new THREE.Color(0x1f1f1f)
  }

  const initLight = () => {
    const ambientLight = new THREE.AmbientLight(0xffffff, 1)
    scene.value?.add(ambientLight)

    const pointLight = new THREE.PointLight(0xffffff, 1)
    camera.value?.add(pointLight)
  }

  const initRender = () => {
    renderer.value = new THREE.WebGLRenderer({ antialias: true, alpha: true })
    renderer.value.setPixelRatio(window.devicePixelRatio)
    renderer.value.setSize(width.value, height.value)
    renderer.value.setAnimationLoop(animate)
    containerRef.value?.appendChild(renderer.value.domElement)
  }

  const initToolCube = async () => {
    const toolGeometry = new THREE.BoxGeometry(1.8, 1.8, 1.8)
    // const rightMap = await loadMap('right')
    // const leftMap = await loadMap('left')
    // const topMap = await loadMap('top')
    // const bottomMap = await loadMap('bottom')
    // const frontMap = await loadMap('front')
    // const backMap = await loadMap('back')
    const [rightMap, leftMap, topMap, bottomMap, frontMap, backMap] =
      await Promise.all([
        loadMap('right'),
        loadMap('left'),
        loadMap('top'),
        loadMap('bottom'),
        loadMap('front'),
        loadMap('back'),
      ])

    toolMaterials.value = [
      new THREE.MeshBasicMaterial({
        map: rightMap,
        transparent: false,
        side: THREE.DoubleSide,
        color: 0x484848,
      }), // 右
      new THREE.MeshBasicMaterial({
        map: leftMap,
        transparent: false,
        side: THREE.DoubleSide,
        color: 0x484848,
      }), // 左
      new THREE.MeshBasicMaterial({
        map: topMap,
        transparent: false,
        side: THREE.DoubleSide,
        color: 0x484848,
      }), // 上
      new THREE.MeshBasicMaterial({
        map: bottomMap,
        transparent: false,
        side: THREE.DoubleSide,
        color: 0x484848,
      }), // 下
      new THREE.MeshBasicMaterial({
        map: frontMap,
        transparent: false,
        side: THREE.DoubleSide,
        color: 0x484848,
      }), // 前
      new THREE.MeshBasicMaterial({
        map: backMap,
        transparent: false,
        side: THREE.DoubleSide,
        color: 0x484848,
      }),
    ]
    toolCube.value = new THREE.Mesh(toolGeometry, toolMaterials.value)

    const edges = new THREE.EdgesGeometry(toolGeometry)
    const lineMaterial = new THREE.LineBasicMaterial({
      color: 0x000000, // 边线颜色
      linewidth: 2, // 线宽（需要启用抗锯齿才有效）
    })

    const wireframe = new THREE.LineSegments(edges, lineMaterial)
    toolCube.value.add(wireframe) // 将线框附加到立方体上

    scene.value?.add(toolCube.value)

    camera.value?.lookAt(toolCube.value!.position)
  }

  const initCamera = () => {
    camera.value = new THREE.OrthographicCamera(-2, 2, 2, -2, 0.1, 10)
    camera.value.position.set(0, 0, 5)
  }

  const initControls = () => {
    controls.value = new OrbitControls(
      camera.value!,
      renderer.value?.domElement,
    )
    controls.value.enabled = false
    controls.value.minDistance = 0.2
  }

  const modelSize = ref({
    x: 0,
    y: 0,
    z: 0,
  })
  const modelCenter = ref({
    x: 0,
    y: 0,
    z: 0,
  })
  const initMainModelInfo = () => {
    if (model.value) {
      const bbox = new THREE.Box3().setFromObject(model.value)
      const size = bbox.getSize(new THREE.Vector3())
      modelSize.value = {
        x: size.x,
        y: size.y,
        z: size.z,
      }
      const center = bbox.getCenter(new THREE.Vector3())
      modelCenter.value = {
        x: center.x,
        y: center.y,
        z: center.z,
      }
    }
  }

  const onClick = (event: MouseEvent) => {
    const raycaster = new THREE.Raycaster()
    const mouse = new THREE.Vector2()

    if (!camera.value || !scene.value || !toolCube.value) return

    // 计算鼠标在canvas中的坐标
    const rect = renderer.value?.domElement.getBoundingClientRect()
    if (!rect) return
    mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
    mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1

    raycaster.setFromCamera(mouse, camera.value)
    const intersects = raycaster.intersectObject(toolCube.value, false)
    if (intersects.length > 0) {
      const faceIndex = intersects[0].face?.materialIndex as number
      const faceArr = ['right', 'left', 'top', 'bottom', 'front', 'back']
      const currentView = faceArr[faceIndex]

      updateViewPoint(currentView)
    }
  }

  // 点击视点工具调用设置主模型视点
  const updateViewPoint = (viewpoint: string) => {
    if (mainControls.value) {
      // 设置 camera 的位置
      const maxSize = Math.max(
        modelSize.value.x,
        modelSize.value.y,
        modelSize.value.z,
      )
      const cameraDistance = maxSize * 3 // 2倍模型尺寸的距离
      const relativePosition = {
        x: 0,
        y: 0,
        z: 0,
      }
      switch (viewpoint) {
        case 'front':
          relativePosition.x = 0
          relativePosition.y = 0
          relativePosition.z = cameraDistance
          break
        case 'back':
          relativePosition.x = 0
          relativePosition.y = 0
          relativePosition.z = -cameraDistance
          break
        case 'left':
          relativePosition.x = -cameraDistance
          relativePosition.y = 0
          relativePosition.z = 0
          break
        case 'right':
          relativePosition.x = cameraDistance
          relativePosition.y = 0
          relativePosition.z = 0
          break
        case 'top':
          relativePosition.x = 0
          relativePosition.y = cameraDistance
          relativePosition.z = 0
          break
        case 'bottom':
          relativePosition.x = 0
          relativePosition.y = -cameraDistance
          relativePosition.z = 0
          break
      }
      const targetPosition = new THREE.Vector3(0, 0, 0)
      targetPosition.copy(modelCenter.value).add(relativePosition)

      const targetLookAt = new THREE.Vector3(0, 0, 0)
      targetLookAt.copy(modelCenter.value)

      console.log('Target Position:', targetPosition)
      gsap.to(mainControls.value.object.position, {
        x: targetPosition.x,
        y: targetPosition.y,
        z: targetPosition.z,
        duration: 0.8,
        ease: 'power2.inOut',
        onUpdate: () => {
          mainControls.value?.object?.lookAt(targetLookAt)
          mainControls.value?.target.set(
            targetLookAt.x,
            targetLookAt.y,
            targetLookAt.z,
          )
          mainControls.value?.update()
        },
        onComplete: () => {
          mainControls.value?.object?.lookAt(targetLookAt)
          mainControls.value?.object?.position.copy(targetPosition)
          mainControls.value?.target.set(
            targetLookAt.x,
            targetLookAt.y,
            targetLookAt.z,
          )
          mainControls.value?.update()
        },
      })
    }
  }

  onBeforeUnmount(() => {
    if (renderer.value) {
      renderer.value.dispose()
      if (renderer.value.domElement.parentNode) {
        renderer.value.domElement.parentNode.removeChild(
          renderer.value.domElement,
        )
      }
    }
  })

  return {
    toolCube,
    renderer,
    scene,
    camera,
    controls,
  }
}
